/**
 * A SceneSet is a container for scenes of a cycle
 */
package soccerscope.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;

import soccerscope.util.GameAnalyzer;
import soccerscope.util.Time;

public class SceneSet
    implements Serializable {

  /**
   * id for serialization.
   */
  private static final long    serialVersionUID = 3256726186435426101L;

  private ArrayList<Scene>     sceneList;

  private int[]                timeTable;

  private boolean[]            validTable;

  private ArrayList<GameEvent> eventList;

  private Class                sceneType;

  /** List of start scenes of changing play modes. */
  private ScenePlayModeList    playModeList;

  /**
   * 
   */
  public SceneSet(
      Class sceneType) {

    // Init the play mode list and put the first scene into it
    this.playModeList = new ScenePlayModeList();

    this.sceneType = sceneType;
    this.sceneList = new ArrayList<Scene>(Time.GAME_TIME);
    this.timeTable = new int[Time.MAX_TIME + 1];
    this.validTable = new boolean[Time.MAX_TIME + 1];
    for (int i = 0; i < Time.MAX_TIME + 1; i++) {
      this.validTable[i] = false;
    }

    if (this.sceneType == ClientScene.class) {
      this.addScene(ClientScene.createScene());
    }
    this.eventList = new ArrayList<GameEvent>();

  }

  /**
   * 
   * 
   * @return
   */
  public int getLimitTime() {

    return ((ClientScene) this.sceneList.get(this.sceneList.size() - 1)).time;
  }

  /**
   * 
   * @param scene
   * @return
   */
  public boolean addScene(Scene scene) {

    if (Time.isValid(scene.time)) {
      if (!this.validTable[scene.time]) {
        this.timeTable[scene.time] = this.sceneList.size();
        this.validTable[scene.time] = true;
      }
      this.sceneList.add(scene);
      this.playModeList.addSceneMode(this.sceneList.size() - 1, scene.time,
          scene.pmode);
      return true;
    }
    return false;
  }

  /**
   * 
   * @return
   */
  public ClientScene firstScene() {

    return (ClientScene) this.sceneList.get(0);
  }

  /**
   * 
   * @return
   */
  public ClientScene lastScene() {

    return (ClientScene) this.sceneList.get(this.sceneList.size() - 1);
  }

  /**
   * 
   * @param index
   * @return
   */
  public ClientScene elementAt(int index) {

    return (ClientScene) this.sceneList.get(index);
  }

  /**
   * 
   * @param clientScene
   * @param time
   */
  public void setScene(ClientScene clientScene,
      int time) {

    this.validTable[time] = true;
    this.sceneList.set(this.timeTable[time], clientScene);
  }

  /**
   * 
   * @param time
   * @return Scene
   */
  public Scene getScene(int time) {

    return this.sceneList.get(this.timeTable[time]);
  }

  /**
   * 
   * @param time
   * @return
   */
  public boolean hasScene(int time) {

    if (Time.isValid(time)) {
      return this.validTable[time];
    }
    return false;
  }

  /**
   * 
   * @param time
   * @return
   */
  public int getIndex(int time) {

    return this.timeTable[time];
  }

  /**
   * 
   * @param clientScene
   * @return
   */
  public int indexOf(ClientScene clientScene) {

    return this.sceneList.indexOf(clientScene);
  }

  /**
   * 
   * @return
   */
  public int size() {

    return this.sceneList.size();
  }

  /**
   * 
   */
  public void clear() {

    this.sceneList.clear();
    this.timeTable = new int[Time.MAX_TIME + 1];
    this.validTable = new boolean[Time.MAX_TIME + 1];
    for (int i = 0; i < Time.MAX_TIME + 1; i++) {
      this.validTable[i] = false;
    }
    this.addScene(ClientScene.createScene());
    this.eventList.clear();
  }

  /**
   * 
   * @return Iterator
   */
  public Iterator iterator() {

    return this.sceneList.iterator();
  }

  /**
   * 
   */
  public void analyze() {

    this.eventList.clear();
    this.eventList = GameAnalyzer.analyze(this);
    Collections.sort(this.eventList);
  }

  /**
   * 
   * @param time
   * @return
   */
  public GameEvent getNextEvent(int time) {

    Iterator it = this.eventList.iterator();
    GameEvent ge;
    while (it.hasNext()) {
      ge = (GameEvent) it.next();
      if (ge.time > time) {
        return ge;
      }
    }
    return null;
  }

  /**
   * 
   * @param time
   * @return
   */
  public GameEvent getPrevEvent(int time) {

    int size = this.eventList.size();
    GameEvent ge;
    for (int i = size - 1; i >= 0; i--) {
      ge = (GameEvent) this.eventList.get(i);
      if (ge.time < time) {
        return ge;
      }
    }
    return null;
  }

  /**
   * This methd adds a new Training-Scene. Because these scenes occurs only
   * single-wise, all other scenes are deleted (only when loading a scene).
   * 
   * @param scene -
   *          the new scene
   */
  public void addTrainingScene(ClientScene scene) {

    this.addScene(scene);
    for (int i = 0; i < this.sceneList.size() - 1; i++) {
      this.sceneList.remove(0);
    }

  }

  /**
   * Returns the list of scenes where the play mode has changed.
   * 
   * @return the list of scenes where the play mode has changed
   */
  public ScenePlayModeList getScenePlayModeList() {

    return this.playModeList;
  }

  /**
   * calculates the newest scene of the given cycle number.
   * 
   * @param cycleNumber
   *          the cycle number
   * @return the last scene with this cycle number or null if the scene does not
   *         exists
   */
  public ClientScene getSceneOfCycle(int cycleNumber) {

    if (this.hasScene(cycleNumber)) {
      int num = this.getIndex(cycleNumber);
      while (this.sceneList.size() > num && this.getScene(num + 1).time == cycleNumber) {
        num++;
      }
      return (ClientScene) this.sceneList.get(num);
    }
    return null;

  }
}

/*
 * $Log: SceneSet.java,v $ Revision 1.2 2006/11/05 13:58:00 wetzker more merging -
 * CLang + MF + some states still missing
 * 
 * Revision 1.1.28.3 2006/10/25 14:33:34 endert Latest SoccerScope Version plus
 * Database ability
 * 
 * Revision 1.1.14.4 2006/08/04 14:00:17 benjaboe PlayerData will be put in the
 * correct cycle not in the last scene
 * 
 * Revision 1.1.14.3 2006/07/29 13:32:42 benjaboe Some parts of the
 * AgentModelLayer can be activated/deactivated. The drawing does not use the
 * LocalScene any more - LocalScene is deleted.
 * 
 * Revision 1.1.14.2 2006/07/24 16:24:47 benjaboe Jump to scenes is possible
 * 
 * Revision 1.1.14.1 2006/07/08 07:40:02 benjaboe Speichern und Laden scheint zu
 * funktionieren
 * 
 * Revision 1.1 2006/03/13 07:37:44 axle moved from ROOT/src for Maven 2
 * Buildsystem and Team/Soccerscope separation
 * 
 * Revision 1.6 2006/03/07 12:46:01 endert Merge after refactoring: - New
 * State-Interface: One Method for each action type - Action Bean removed -
 * ActionFactorys for helper methods, States calculate main-Action themselves -
 * formatted code - added State-List in Monitor (Context-Menu of Player) - other
 * smaller stuff
 * 
 * Revision 1.5.2.1 2006/02/25 22:07:24 wetzker formated
 * 
 * Revision 1.5 2006/02/24 18:53:56 wetzker used enums for Play_modes and
 * Referee_messages - still has to be improved after creation of new
 * Play_mode-Model - tagged old version removed millions of warnings
 * 
 * Revision 1.4 2006/02/22 16:04:43 endert This is done: - Rebound SoccerScope
 * to Agents (can be added or removed in config-file) - Situations now all
 * extend abstract class Situation - Refactorings: ActionBean _ removed from
 * Attributes - SoccerScope will automatically connect to host given in
 * Start-Call - Trainer uses the same host as soccerscope - Removed unused stuff
 * (old confs, bat, etc.) - Code formatted (good luck when merging) - organized
 * imports - all that i forgot to mention here Revision 1.3 2005/10/25 20:51:37
 * endert Added Training-Editor to SoccerScope, restructuring in some old
 * classes and some experimental stuff (goals, commitments, mental model)
 * 
 * Revision 1.2.4.1 2005/10/11 18:29:52 endert TrainingModel moved to WorldModel
 * (of SoccerScope)
 * 
 * Revision 1.2 2005/10/01 13:39:15 wetzker organized imports
 * 
 * Revision 1.1 2005/04/20 10:39:03 endert Fresh Team Repository installation
 * from /home/e/endert/Robocup to here.
 * 
 * Revision 1.4 2005/03/13 14:47:26 haeder * some modifications to reduce the
 * number of warnings ;-) - removed unreadable comments
 * 
 * Revision 1.3 2005/02/06 07:17:27 maketi Added soccerscope with connection to
 * our world model
 * 
 * Revision 1.8 2003/06/09 09:00:34 newone jump��5
 * 
 * Revision 1.7 2002/09/17 07:46:19 koji
 * WatchBall��ZoomBall�Υ��������ѹ���Publish�ѤΥѥͥ��ɲá�������ν���
 * �Υ�����򥫥���Ȥ��Ƥ��ʤ��ä��Τ�5
 * 
 * Revision 1.6 2002/09/12 11:25:37 koji
 * ��ײ��ϡ�����ǽ���ɲá������ե�����졼�����ե������б�
 * 
 * Revision 1.5 2002/09/09 09:56:35 koji
 * Preference��GUI��.,soccerscope.conf��Ƴ��
 * 
 * Revision 1.4 2002/09/06 10:05:50 koji Preference��GUI��d�äȺ�.
 * 
 * Revision 1.3 2002/09/05 09:46:33 koji
 * ���٥�ȥ����u�ǽ���ɲ�
 * 
 * Revision 1.2 2002/08/30 10:47:31 koji bmpviewer����Jimi�б�
 * 
 * Revision 1.1.1.1 2002/03/01 14:12:54 koji CVS�����
 * 
 */
